#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QTcpServer>
#include <QtCore/QSettings>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    socketFromClient = 0;
    socketToServer = 0;
    server = 0;

    QSettings settings;
    ui->spinBoxClientPort->setValue(settings.value("settings/clientport").toInt());
    ui->spinBoxServerPort->setValue(settings.value("settings/serverport").toInt());
    ui->lineEditServerIp->setText(settings.value("settings/serverip", "127.0.0.1").toString());
    ui->checkBox->setChecked(settings.value("settings/showashex").toBool());

    on_pushButtonConnect_clicked();
}

MainWindow::~MainWindow()
{
    QSettings settings;
    settings.setValue("settings/clientport", ui->spinBoxClientPort->value());
    settings.setValue("settings/serverport", ui->spinBoxServerPort->value());
    settings.setValue("settings/serverip", ui->lineEditServerIp->text());
    settings.setValue("settings/showashex", ui->checkBox->isChecked());

    delete ui;
}

void MainWindow::setOrientation(ScreenOrientation orientation)
{
#if defined(Q_OS_SYMBIAN)
    // If the version of Qt on the device is < 4.7.2, that attribute won't work
    if (orientation != ScreenOrientationAuto) {
        const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
        if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
            qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
            return;
        }
    }
#endif // Q_OS_SYMBIAN

    Qt::WidgetAttribute attribute;
    switch (orientation) {
#if QT_VERSION < 0x040702
    // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
    case ScreenOrientationLockPortrait:
        attribute = static_cast<Qt::WidgetAttribute>(128);
        break;
    case ScreenOrientationLockLandscape:
        attribute = static_cast<Qt::WidgetAttribute>(129);
        break;
    default:
    case ScreenOrientationAuto:
        attribute = static_cast<Qt::WidgetAttribute>(130);
        break;
#else // QT_VERSION < 0x040702
    case ScreenOrientationLockPortrait:
        attribute = Qt::WA_LockPortraitOrientation;
        break;
    case ScreenOrientationLockLandscape:
        attribute = Qt::WA_LockLandscapeOrientation;
        break;
    default:
    case ScreenOrientationAuto:
        attribute = Qt::WA_AutoOrientation;
        break;
#endif // QT_VERSION < 0x040702
    };
    setAttribute(attribute, true);
}

void MainWindow::showExpanded()
{
#if defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR)
    showFullScreen();
#elif defined(Q_WS_MAEMO_5)
    showMaximized();
#else
    show();
#endif
}

void MainWindow::on_pushButtonConnect_clicked()
{
    // Cleanup any active connections.
    delete server;
    delete socketFromClient;
    delete socketToServer;
    socketFromClient = 0;
    socketToServer = 0;

    // Start listening.
    server = new QTcpServer(this);
    connect(server, SIGNAL(newConnection()), this, SLOT(connectionFromClient()));
    if (server->listen(QHostAddress::Any, ui->spinBoxClientPort->value()))
        ui->statusBar->showMessage(tr("Listening on %1...").arg(ui->spinBoxClientPort->value()));
    else
        ui->statusBar->showMessage(tr("Cound not listen on %1").arg(ui->spinBoxClientPort->value()));

    // Clear any text.
    ui->textEdit->setText("");
}

void MainWindow::connectionFromClient()
{
    // Get the connection.
    socketFromClient = server->nextPendingConnection();
    socketFromClient->setParent(this);
    connect(socketFromClient, SIGNAL(readyRead()), this, SLOT(dataFromClient()));

    // Stop listening.
    delete server;
    server = 0;

    // Connect to the server.
    socketToServer = new QTcpSocket(this);
    socketToServer->connectToHost(ui->lineEditServerIp->text(), ui->spinBoxServerPort->text().toInt());
    connect(socketToServer, SIGNAL(readyRead()), this, SLOT(dataFromServer()));
    connect(socketToServer, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(connectionToServerFailed()));
    connect(socketToServer, SIGNAL(connected()), SLOT(connectionToServerSucceeded()));

    ui->statusBar->showMessage(tr("Incoming connection from client, now connecting to server..."));
}

static char toHexDigit(char ch)
{
    return ch<10 ? ch+'0' : ch-10+'A';
}

static QString toHex(const QByteArray &data)
{
    QString str;
    str.reserve(5*data.size());
    foreach (unsigned char byte, data) {
        str += toHexDigit(byte & 0xf);
        str += toHexDigit(byte >> 4);
        str += ' ';
    }
    return str;
}

void MainWindow::dataFromClient()
{
    // If we're not yet connected to the server, don't send the
    // data, otherwise it will be lost.
    if (socketToServer->state() != QAbstractSocket::ConnectedState) {
        return;
    }

    QByteArray a = socketFromClient->readAll();
    ui->textEdit->append("<font color=\"red\">" + (ui->checkBox->isChecked() ? toHex(a) : Qt::escape(a)) + "</font>");
    socketToServer->write(a);
}

void MainWindow::dataFromServer()
{
    QByteArray a = socketToServer->readAll();
    ui->textEdit->append("<font color=\"blue\">" + (ui->checkBox->isChecked() ? toHex(a) : Qt::escape(a)) + "</font>");
    socketFromClient->write(a);
}

void MainWindow::connectionToServerFailed()
{
    ui->statusBar->showMessage(tr("Cound not connect to server."));
}

void MainWindow::connectionToServerSucceeded()
{
    // Send any pending data that might have arrived from the client while we
    // were still connecting.
    QByteArray a = socketFromClient->readAll();
    ui->textEdit->append("<font color=\"red\">" + (ui->checkBox->isChecked() ? toHex(a) : Qt::escape(a)) + "</font>");
    socketToServer->write(a);

    ui->statusBar->showMessage(tr("Connected to server."));
}
